﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DownloadBook {
    public partial class FrmMergeContent : Form {
        private Book m_Book;
        private Regex m_Regex;
        private int m_GroupId;
        private Regex m_RegBr;
        private Regex m_RegCr;
        private Regex m_ReglfOne;
        private Regex m_ReglfThree;
        private Regex m_RegP;
        private Regex m_RegStartSpace;
        private Regex m_RegEndSpace;
        private Regex m_RegSpan;
        private Regex m_RegRemove;

        /// <summary>
        /// 左双引号
        /// </summary>
        private Regex m_RegLdquo;
        /// <summary>
        /// 右双引号
        /// </summary>
        private Regex m_RegRdquo;

        /// <summary>
        /// 省略号的一半
        /// </summary>
        private Regex m_RegHellipHalf;

        /// <summary>
        /// 破折号一半
        /// </summary>
        private Regex m_RegMdashHalf;


        private MergeConfig m_MergeConfig;
        private MergeConfigServer m_MergeConfigService;


        private string m_OutputFilePath;
        public string outputFilePath {
            get {
                if (string.IsNullOrEmpty(m_OutputFilePath)) {
                    string outFileName = string.Format("{0}.txt", m_Book.name);
                    string outDirectory = Path.Combine(Environment.CurrentDirectory, "txt");
                    if (!Directory.Exists(outDirectory)) {
                        Directory.CreateDirectory(outDirectory);
                    }
                    m_OutputFilePath = Path.Combine(outDirectory, outFileName);
                }
                return m_OutputFilePath;
            }
        }


        public FrmMergeContent() {
            InitializeComponent();
        }

        public FrmMergeContent(Book book) : this(){
            this.m_Book = book;
            m_MergeConfigService = MergeConfigServer.instance;
        }

        private void FrmMergeContent_Load(object sender, EventArgs e) {
            SelectAllSupport.Bind(txtAuthor);
            SelectAllSupport.Bind(txtExtractPreview);
            SelectAllSupport.Bind(txtIntroduction);
            SelectAllSupport.Bind(txtOriginHtml);
            SelectAllSupport.Bind(txtRegContent);
            SelectAllSupport.Bind(txtRegContentGroupId);
            SelectAllSupport.Bind(txtRegRemove);

            LoadConfig();
            LoadDefaultOriginHtml(); //载入默认的原始html
            
            lblMsg.Text = "准备就绪";

            if (!string.IsNullOrEmpty(m_MergeConfig.regContent)) {//如果合并正则表达式不为空
                ExtractPreview();//自动调用合并预览
            }
        }


        /// <summary>
        /// 载入配置按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnLoadConfig_Click(object sender, EventArgs e) {
            LoadConfig();
        }
        /// <summary>
        /// 保存合并配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtSaveConfig_Click(object sender, EventArgs e) {
            UpdateConfig();
        }

        /// <summary>
        /// 预览按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExtractPreview_Click(object sender, EventArgs e) {
            ExtractPreview();
        }
        
        /// <summary>
        /// 合并按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnMergeTxt_Click(object sender, EventArgs e) {
            CreateMatch();
            UpdateConfig();

            string author = txtAuthor.Text;
            string introduction = txtIntroduction.Text;
            Thread thread = new Thread(()=> {
                MerageText(author, introduction, (msg)=> {
                    this.Invoke(new EventHandler(delegate {
                        lblMsg.Text = msg;
                    }));
                });
            });
            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// 合并预览
        /// </summary>
        private void ExtractPreview() {
            CreateMatch();
            string str;
            ExtractContent(txtOriginHtml.Text, out str);
            txtExtractPreview.Text = str;
        }


        /// <summary>
        /// 载入默认原始html
        /// </summary>
        private void LoadDefaultOriginHtml() {
            if (Directory.Exists(m_Book.htmlDirectory)) {
                for (int i = 0; i < m_Book.contentList.Count; i++) {
                    Content content = m_Book.contentList[i];
                    string html = GetContentHtml(content);
                    if (!string.IsNullOrEmpty(html)) {
                        txtOriginHtml.Text = html;
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 合并章节
        /// </summary>
        /// <param name="author"></param>
        /// <param name="introduction"></param>
        /// <param name="updateMessage"></param>
        private void MerageText(string author, string introduction, Action<string> updateMessage) {
            if (string.IsNullOrEmpty(m_Book.name)) {
                MessageBox.Show("请先输入书名", "出错了", MessageBoxButtons.OK, MessageBoxIcon.Error);
            } else {


                FileStream fileStream = new FileStream(outputFilePath, FileMode.Create);
                WriteString(fileStream, string.Format("《{0}》", m_Book.name));
                WriteString(fileStream, "\r\n");
                WriteString(fileStream, "作者：" + (string.IsNullOrEmpty(author) ? "无" : author));
                WriteString(fileStream, "\r\n");
                WriteString(fileStream, "简介：");
                WriteString(fileStream, "\r\n");
                WriteString(fileStream, (string.IsNullOrEmpty(introduction) ? "无" : introduction));
                //简介之后接两个空格
                WriteString(fileStream, "\r\n");
                WriteString(fileStream, "\r\n");

                int nErrorCount = 0;
                string msg = "";
                for (int i = 0; i < m_Book.contentList.Count; i++) {
                    Content content = m_Book.contentList[i];
                    string filePath = Path.Combine(m_Book.htmlDirectory, content.GetFileName());

                    if (!m_Book.ignoreContentTitle) {//如果不忽略章节标题才需要输出章节标题
                        WriteString(fileStream, content.title);
                        WriteString(fileStream, "\r\n");
                    }
                    if (!File.Exists(filePath)) {
                        nErrorCount++;
                        WriteString(fileStream, "这个章节未下载，请原网址查看：" + content.url);
                    } else {
                        string html = GetContentHtml(content);
                        string contentText;
                        if (!ExtractContent(html, out contentText)) {
                            nErrorCount++;
                            WriteString(fileStream, "提取章节内容失败，请原网址查看：" + content.url);
                        } else {
                            WriteString(fileStream, contentText);//写入章节内容
                        }
                    }
                    if (!m_Book.ignoreContentTitle) {//如果不忽略章节标题才需要输出章节末尾的两个空行
                        WriteString(fileStream, "\r\n");
                        WriteString(fileStream, "\r\n");
                    }

                    msg = string.Format("正在合并章节：{0}/{1} {2}", i + 1, m_Book.contentList.Count, content.title);
                    Console.WriteLine(msg);
                    if(updateMessage != null){
                        updateMessage.Invoke(msg);
                    }
                }
                fileStream.Flush();
                fileStream.Close();

                msg = string.Format("合并完成，提取失败的章节个数为{0}个", nErrorCount);
                Console.WriteLine(msg);
                if(updateMessage != null){
                    updateMessage.Invoke(msg);
                }
                MessageBox.Show(msg, "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        /// <summary>
        /// 获取章节的Html
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        private string GetContentHtml(Content content) {
            string result = "";
            string filePath = Path.Combine(m_Book.htmlDirectory, content.GetFileName());
            if (File.Exists(filePath)) {
                byte[] buffer = File.ReadAllBytes(filePath);
                if (buffer != null) {
                    if (buffer.Length > 0) {
                        result = Encoding.Default.GetString(buffer);
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 检查是不是乱码
        /// </summary>
        /// <param name="txt"></param>
        /// <returns></returns>
        private bool isLuan(string txt) {
            byte [] bytes = Encoding.UTF8.GetBytes(txt);
            //239 191 189
            for (var i = 0; i < bytes.Length; i++) {
                if (i < bytes.Length - 3) {
                    if (bytes[i] == 239 && bytes[i + 1] == 191 && bytes[i + 2] == 189) {
                        return true;
                    } else if (bytes[i] == 233 && bytes[i + 1] == 148 && bytes[i + 2] == 152) {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 写入字符串
        /// </summary>
        /// <param name="fileStream"></param>
        /// <param name="str"></param>
        private void WriteString(FileStream fileStream, string str) {
            byte[] buffer = Encoding.UTF8.GetBytes(str);
            fileStream.Write(buffer, 0, buffer.Length);
        }

        /// <summary>
        /// 创建正则表达式匹配对象
        /// </summary>
        private void CreateMatch() {
            m_GroupId = Convert.ToInt32(txtRegContentGroupId.Text);
            m_Regex = new Regex(txtRegContent.Text, RegexOptions.IgnoreCase);
            m_RegBr = new Regex("<[/]?[\\s]*?br[\\s]*?[/]?>", RegexOptions.IgnoreCase);
            m_RegCr = new Regex("\r", RegexOptions.IgnoreCase);

            //&ldquo;(*)&rdquo; 双引号
            m_RegLdquo = new Regex("&ldquo;", RegexOptions.IgnoreCase);
            m_RegRdquo = new Regex("&rdquo;", RegexOptions.IgnoreCase);

            //&hellip; 省略号
            m_RegHellipHalf =new Regex("&hellip;", RegexOptions.IgnoreCase);
            
            //&mdash;—
            m_RegMdashHalf = new Regex("&mdash;", RegexOptions.IgnoreCase);

            m_ReglfOne = new Regex("\n", RegexOptions.IgnoreCase);
            m_ReglfThree = new Regex("\n\n\n", RegexOptions.IgnoreCase);

            m_RegP = new Regex("<[/]{0,1}p>", RegexOptions.IgnoreCase);
            m_RegStartSpace = new Regex("^[\n]{1,}", RegexOptions.IgnoreCase);
            m_RegEndSpace = new Regex("[\n]{1,}$", RegexOptions.IgnoreCase);
            m_RegSpan = new Regex("&nbsp;", RegexOptions.IgnoreCase);
            if (!string.IsNullOrEmpty(txtRegRemove.Text)) {
                m_RegRemove = new Regex(txtRegRemove.Text, RegexOptions.IgnoreCase);
            }
        }

        /// <summary>
        /// 载入配置
        /// </summary>
        private void LoadConfig() {
            LoadMergeConfig();//载入合并配置
            txtAuthor.Text = m_Book.author;
            txtIntroduction.Text = m_Book.introduction;
            chkIgnoreContentTitle.Checked = m_Book.ignoreContentTitle;
        }
        /// <summary>
        /// 更新配置
        /// </summary>
        private void UpdateConfig() {
            m_Book.author = txtAuthor.Text;
            m_Book.introduction = txtIntroduction.Text;
            m_Book.ignoreContentTitle = chkIgnoreContentTitle.Checked;
            UpdateMergeConfig();
        }


        /// <summary>
        /// 载入合并配置
        /// </summary>
        private void LoadMergeConfig() {
            m_MergeConfig = m_MergeConfigService.GetMergeConfig(m_Book.url);
            txtRegContent.Text = m_MergeConfig.regContent;
            txtRegContentGroupId.Text = "" + m_MergeConfig.regContentGroupId;
            txtRegRemove.Text = m_MergeConfig.regRemove;
        }

        /// <summary>
        /// 更新合并配置
        /// </summary>
        private void UpdateMergeConfig() {
            m_MergeConfig.hostName = HtmlUtil.GetHostName(m_Book.url);
            m_MergeConfig.regContent = txtRegContent.Text;
            m_MergeConfig.regContentGroupId = Convert.ToInt32(txtRegContentGroupId.Text);
            m_MergeConfig.regRemove = txtRegRemove.Text;
            if (m_MergeConfig.isDicty) {
                m_MergeConfigService.SaveConfig();
            }
        }

        /// <summary>
        /// 提取章节内容
        /// </summary>
        /// <param name="html"></param>
        /// <param name="outStr"></param>
        /// <returns></returns>
        private bool ExtractContent(string html, out string outStr) {
            bool result = false;
            outStr = "";
            if (!string.IsNullOrEmpty(html)) {
                Match match = m_Regex.Match(html);
                if (!match.Success) {
                    outStr = "提取失败，请重新设置提取目录的正则表达式";
                } else if (match.Groups.Count < m_GroupId) {
                    outStr = "提取失败，分组不够，分组id不正确";
                } else {
                    outStr = match.Groups[m_GroupId].ToString();
                    outStr = FormatContentText(outStr);
                    result = true;
                }
            }
            return result;
        }

        /// <summary>
        /// 格式化章节内容
        /// </summary>
        /// <param name="str"></param>
        private string FormatContentText(string str) {
            string result = str;
            if (!string.IsNullOrEmpty(str)) {

                if (m_RegRemove != null) {
                    str = m_RegRemove.Replace(str, "");//移除用户指定的内容
                }

                str = m_RegSpan.Replace(str, " ");//替换空格
                str = m_RegBr.Replace(str, "\n");//替换<br />为换行
                str = m_RegP.Replace(str, "\n");//替换<br />为换行
                str = m_RegCr.Replace(str, "");//移除\r

                str = m_ReglfOne.Replace(str, "\n\n");//替换一个换行为两个
                string strTemp = str;
                for(;;) {
                    strTemp = m_ReglfThree.Replace(str, "\n\n");//替换三个换行为两个
                    if(strTemp == str) {
                        break;
                    }
                    str = strTemp;
                }


                //html 特殊字符转码
                str = this.HtmlTranscodingSpecialCharacters(str);
                

                if(m_RegRemove != null) {
                    str = m_RegRemove.Replace(str, "");//移除用户指定的内容
                }

                string [] lines = str.Split('\n');
                StringBuilder sb = new StringBuilder();
                for(int i = 0; i < lines.Length; i++) {
                    string line = lines[i].Trim();
                    if (!string.IsNullOrEmpty(line)) {
                        if(sb.Length > 0) {
                            sb.Append("\n");
                        }
                        sb.Append("    ");
                        sb.Append(line);
                    }
                }
                str = sb.ToString();
                sb.Clear();


                str = m_RegStartSpace.Replace(str, "");//移除开头空行
                str = m_RegEndSpace.Replace(str, "");//移除末尾空行

                Regex m_ReglfToCrlf = new Regex("\n", RegexOptions.IgnoreCase);
                str = m_ReglfToCrlf.Replace(str, "\r\n");//替换换行为回车换行
                result = str;
            }
            return result;
        }

        /// <summary>
        /// Html 特殊字符转码
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        private String HtmlTranscodingSpecialCharacters(String html){
            String str = html;
            if(!String.IsNullOrEmpty(str)){
                if(str.Contains("&")){//如果包含这个字符，才有必要执行下面的代码
                    str = m_RegLdquo.Replace(str, "“");//左双引号
                    str = m_RegRdquo.Replace(str, "”");//右双引号
                    str = m_RegHellipHalf.Replace(str, "…");//省略号一半
                    str = m_RegMdashHalf.Replace(str, "…");//省略号一半
                }
            }
            return str;
        }
        



        private void btnDisplayOutputFile_Click(object sender, EventArgs e) {
            try {
                if (!File.Exists(outputFilePath)) {
                    throw new Exception("还未合并下载的章节，请先合并！");
                }else {
                    Process process = Process.Start("Explorer", string.Format(@"/select, ""{0}""", outputFilePath));
                    process.WaitForExit();
                }
            }catch(Exception ex) {
                MessageBox.Show(ex.Message, "出错了", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

    }
}
